package com.wjm.myalipayplugin;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.IntentFilter;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.content.res.Resources;

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.List;

import dalvik.system.DexClassLoader;

public class PluginManager {
    private Context context;
    private static final PluginManager ourInstance = new PluginManager();
    private PackageInfo packageArchiveInfo;
    private DexClassLoader dexClassLoader;
    private Resources resources;

    private PluginManager() {
    }

    public static PluginManager getInstance() {
        return ourInstance;
    }

    public void setContext(Context context) {
        this.context = context;
    }

    public void loadPath(Context context) {
        File plugin = context.getDir("plugin", Context.MODE_APPEND);//插件在plugin文件夹中
        String name = MainActivity.apkName;//插件apk名
        String absolutePath = new File(plugin, name).getAbsolutePath();
        PackageManager packageManager = context.getPackageManager();
        packageArchiveInfo = packageManager.getPackageArchiveInfo(absolutePath, PackageManager.GET_ACTIVITIES);//使用pm通过apk文件路径去获取此apk里的activity，就是获取到插件apk中的PackageInfo

        //因为插件apk是未安装的，那么要加载它的类和res就要想办法了，弄到插件apk的类加载器和res资源
        File dex = context.getDir("dex", Context.MODE_APPEND);
        //插件apk的类加载器
        dexClassLoader = new DexClassLoader(absolutePath, dex.getAbsolutePath(), null, context.getClassLoader());//实例dexclassloader,参数：apk路径，dex路径，null,宿主apk类加载器

        //插件apk的res资源 resoure
        try {
            AssetManager assetManager = AssetManager.class.newInstance();
            Method addAssetPath = AssetManager.class.getMethod("addAssetPath", String.class);
            addAssetPath.invoke(assetManager, absolutePath);//反射实例AssetManager
            //插件resoure
            resources = new Resources(assetManager, context.getResources().getDisplayMetrics(), context.getResources().getConfiguration());
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        }

        //插件中静态广播的使用
        parseReceivers(context, absolutePath);

    }

    private void parseReceivers(Context context, String path) {

//        Package对象
//        PackageParser pp = new PackageParser();

//        PackageParser.Package  pkg = pp.parsePackage(scanFile, parseFlags);


        try {

            Class   packageParserClass = Class.forName("android.content.pm.PackageParser");
            Method parsePackageMethod = packageParserClass.getDeclaredMethod("parsePackage", File.class, int.class);
            Object packageParser = packageParserClass.newInstance();
            Object packageObj=  parsePackageMethod.invoke(packageParser, new File(path), PackageManager.GET_ACTIVITIES);

            Field receiverField=packageObj.getClass().getDeclaredField("receivers");
//拿到receivers  广播集合    app存在多个广播   集合  List<Activity>  name  ————》 ActivityInfo   className
            List receivers = (List) receiverField.get(packageObj);

            Class<?> componentClass = Class.forName("android.content.pm.PackageParser$Component");
            Field intentsField = componentClass.getDeclaredField("intents");


            // 调用generateActivityInfo 方法, 把PackageParser.Activity 转换成
            Class<?> packageParser$ActivityClass = Class.forName("android.content.pm.PackageParser$Activity");
//            generateActivityInfo方法
            Class<?> packageUserStateClass = Class.forName("android.content.pm.PackageUserState");
            Object defaltUserState= packageUserStateClass.newInstance();
            Method generateReceiverInfo = packageParserClass.getDeclaredMethod("generateActivityInfo",
                    packageParser$ActivityClass, int.class, packageUserStateClass, int.class);
            Class<?> userHandler = Class.forName("android.os.UserHandle");
            Method getCallingUserIdMethod = userHandler.getDeclaredMethod("getCallingUserId");
            int userId = (int) getCallingUserIdMethod.invoke(null);

            for (Object activity : receivers) {
                ActivityInfo info= (ActivityInfo) generateReceiverInfo.invoke(packageParser,  activity,0, defaltUserState, userId);
                BroadcastReceiver broadcastReceiver= (BroadcastReceiver) dexClassLoader.loadClass(info.name).newInstance();
                List<? extends IntentFilter> intents= (List<? extends IntentFilter>) intentsField.get(activity);
                for (IntentFilter intentFilter : intents) {
                    context.registerReceiver(broadcastReceiver, intentFilter);
                }
            }
            //generateActivityInfo
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

    public PackageInfo getPackageInfo() {
        return packageArchiveInfo;
    }
    public Resources getResources() {
        return resources;
    }

    public DexClassLoader getDexClassLoader() {
        return dexClassLoader;
    }
}
